// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <pollux/common/testutil/scoped_test_time.h>

#include <pollux/common/base/exceptions.h>

namespace kumo::pollux::common::testutil {
    bool ScopedTestTime::enabled_ = false;
    std::optional<uint64_t> ScopedTestTime::testTimeNs_ = {};

    ScopedTestTime::ScopedTestTime() {
#ifndef NDEBUG
        POLLUX_CHECK(!enabled_, "Only one ScopedTestTime can be active at a time");
        enabled_ = true;
#else
  POLLUX_UNREACHABLE("ScopedTestTime should only be used in debug mode");
#endif
    }

    ScopedTestTime::~ScopedTestTime() {
        testTimeNs_.reset();
        enabled_ = false;
    }

    void ScopedTestTime::setCurrentTestTimeSec(uint64_t currentTimeSec) {
        setCurrentTestTimeNano(currentTimeSec * 1'000'000'000UL);
    }

    void ScopedTestTime::setCurrentTestTimeMs(uint64_t currentTimeMs) {
        setCurrentTestTimeNano(currentTimeMs * 1'000'000UL);
    }

    void ScopedTestTime::setCurrentTestTimeMicro(uint64_t currentTimeUs) {
        setCurrentTestTimeNano(currentTimeUs * 1'000UL);
    }

    void ScopedTestTime::setCurrentTestTimeNano(uint64_t currentTimeNs) {
        testTimeNs_ = currentTimeNs;
    }

    std::optional<uint64_t> ScopedTestTime::getCurrentTestTimeSec() {
        return testTimeNs_.has_value()
                   ? std::make_optional(*testTimeNs_ / 1'000'000'000L)
                   : testTimeNs_;
    }

    std::optional<uint64_t> ScopedTestTime::getCurrentTestTimeMs() {
        return testTimeNs_.has_value()
                   ? std::make_optional(*testTimeNs_ / 1000'000L)
                   : testTimeNs_;
    }

    std::optional<uint64_t> ScopedTestTime::getCurrentTestTimeMicro() {
        return testTimeNs_.has_value()
                   ? std::make_optional(*testTimeNs_ / 1000L)
                   : testTimeNs_;
    }

    std::optional<uint64_t> ScopedTestTime::getCurrentTestTimeNano() {
        return testTimeNs_;
    }
} // namespace kumo::pollux::common::testutil
